package info.empathymobile.forecast.testenv.business;

import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import info.empathymobile.forecast.testenv.beans.TestBaseData;
import info.empathymobile.forecast.testenv.beans.TestLog;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.net.Uri;

public class ServerConnection {
	public static final String EMPATHY_SERVER_DOMAIN = "192.168.43.217";
	public static final String GET_NOT_CHARGING_DURATION_BY_TIME_TEST_DATA_PATH = "get_not_charging_duration_by_time_test_data";
	public static final String GET_NO_CONNECTIVITY_DURATION_BY_TIME_TEST_DATA_PATH = "get_no_connectivity_duration_by_time_test_data";
	public static final String SAVE_TEST_LOGS_PATH = "save_test_logs";
	
	public static final String AUTH_KEY_PARAM = "auth_key";
	
	//PARAMS FOR TestBaseData Requests
	public static final String USER_UUID_PARAM = "user_uuid";
	public static final String THRESHOLD_PARAM = "threshold";
	public static final String DAYS_AGO_PARAM = "days_ago";
	public static final String NET_TYPE_PARAM = "net_type";
	
	//PARAMS FOR TestLog Requests
	public static final String TEST_LOGS_PARAM = "test_logs";
	
	private String authKey;
	
	public ServerConnection(String authKey){
		this.authKey = authKey;
	}

	private Uri.Builder buildFreshHttpGetUriBuilder() {
		Uri.Builder httpGetUriBuilder = new Uri.Builder();
		httpGetUriBuilder.scheme("http");
		httpGetUriBuilder.encodedAuthority(EMPATHY_SERVER_DOMAIN);
		httpGetUriBuilder.appendQueryParameter(AUTH_KEY_PARAM, this.authKey);
		
		return httpGetUriBuilder;
	}
	
	public String sendRequest(HttpUriRequest httpRequest){
		try {
			return getJsonResponse(new DefaultHttpClient().execute(httpRequest));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private String getJsonResponse(HttpResponse response) throws IOException {
		String jsonResult = null;
		HttpEntity entity = response.getEntity();
		if (entity != null) {
		    InputStream instream = entity.getContent();
		    jsonResult = convertStreamToString(instream);
		    instream.close();
		}
		
		return jsonResult;
	}
	
	private String convertStreamToString(InputStream is) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
	

	public List<TestBaseData> getNewTestBaseDataFromServer(List<TestBaseData> params) {
		List<TestBaseData> requestedTestBaseData = new ArrayList<TestBaseData>();
		JSONDeserializer<ArrayList<Integer>> deserializer = new JSONDeserializer<ArrayList<Integer>>();
		
		for (TestBaseData param : params) {
			Uri.Builder httpGetUriBuilder = buildFreshHttpGetUriBuilder();
			
			String serverMethodPath = null;
			httpGetUriBuilder.appendQueryParameter(USER_UUID_PARAM, param.getUserUUID());
			httpGetUriBuilder.appendQueryParameter(THRESHOLD_PARAM, Integer.toString(param.getUsedThreshold()));
			httpGetUriBuilder.appendQueryParameter(DAYS_AGO_PARAM, Integer.toString(param.getUsedDaysAgo()));
			
			if(param.getBaseDataType().equals(TestBaseData.BATTERY_DATA)){
				serverMethodPath = GET_NOT_CHARGING_DURATION_BY_TIME_TEST_DATA_PATH;
			}
			else if(param.getBaseDataType().equals(TestBaseData.CONNECTIVITY_3G_DATA)) {
				httpGetUriBuilder.appendQueryParameter(NET_TYPE_PARAM, "1");
				serverMethodPath = GET_NO_CONNECTIVITY_DURATION_BY_TIME_TEST_DATA_PATH;
			}
			else if(param.getBaseDataType().equals(TestBaseData.CONNECTIVITY_WIFI_DATA)){
				httpGetUriBuilder.appendQueryParameter(NET_TYPE_PARAM, "0");
				serverMethodPath = GET_NO_CONNECTIVITY_DURATION_BY_TIME_TEST_DATA_PATH;
			}
			
			if(serverMethodPath != null){
				httpGetUriBuilder.appendPath(serverMethodPath);
				HttpGet httpGet = new HttpGet(); 
				httpGet.setURI(URI.create(httpGetUriBuilder.build().toString()));
				String jsonResponse = sendRequest(httpGet);
				if(jsonResponse != null){
					try {
						ArrayList<Integer> timeSeriesData = deserializer.deserialize(jsonResponse);
						TestBaseData newTestBaseData = new TestBaseData(param, timeSeriesData);
						requestedTestBaseData.add(newTestBaseData);
					} catch (Exception e) {
						//Do nothing when a class cast exception occur on deserialization because its a non serializable http result
					}
				}
			}
		}
		
		return requestedTestBaseData;
	}

	public List<Integer> sendTestLogsToServer(List<TestLog> allTestLogOnDB) {
		try {
			HttpPost httpPost = new HttpPost("http://" + EMPATHY_SERVER_DOMAIN + "/" + SAVE_TEST_LOGS_PATH);
			httpPost.setHeader("Content-Type","application/json");
			httpPost.setHeader("Accept", "application/json");
			
			JSONSerializer serializer = new JSONSerializer();
			
			String jsonEntries = serializer.exclude("*.class").deepSerialize(allTestLogOnDB);
			
			JSONObject jsonObj = new JSONObject();
			jsonObj.put(TEST_LOGS_PARAM, new JSONArray(jsonEntries));
			jsonObj.put(AUTH_KEY_PARAM, authKey);
			
			httpPost.setEntity(new StringEntity(jsonObj.toString(), "UTF-8"));
			
			String jsonResponse = getJsonResponse(new DefaultHttpClient().execute(httpPost));
			
			if(jsonResponse != null){
				ArrayList<Integer> successfulSyncIds = new ArrayList<Integer>();
				try {
					successfulSyncIds = new JSONDeserializer<ArrayList<Integer>>().deserialize(jsonResponse);
				} catch (Exception e) {
					//Do nothing when a class cast exception occur on deserialization because its a non serializable http result
				}
				return successfulSyncIds;
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}
